package ann;

import java.util.ArrayList;
import java.util.List;

import activation.ActivationFunction;

public class Layer extends Module{
	
	private List<Node> nodes;
	private ActivationFunction activationFunction;
	private String name;
	//private boolean learningIsEnabled;
	//private boolean isActive;
	//private int maxSettlingRounds;
	
	public Layer(int size,ActivationFunction activationFunction, String name)
	{
		super();
		assert size>0 && size < 100;
		
		this.name = name;
		nodes = new ArrayList<Node>();
		this.activationFunction = activationFunction;
		for(int i  = 0; i<size; i++)
			nodes.add(new Node(this));
	}

	public void setInput(int i, double j) {
		
		assert i<nodes.size();
		
		nodes.get(i).setMembranePotential(j);
	}

	public int getInputSize() {
		return nodes.size();
	}

	public int getOutputSize() {
		return nodes.size();
	}

	public void updateInput() {
		List<Link> totalInputLinks = getTotalInputLinks();
		
		if(totalInputLinks.size()==0)
			return;
		
		for(Node node : nodes)
			node.setMembranePotential(0.0);
		
		for(Link link: totalInputLinks)
		{
			Module fromModule = link.getFromModule();
			for(Arc arc: link)
			{
				incrementInput(arc.getToIndex(),fromModule.getOutput(arc.getFromIndex())*arc.getWeight());
			}
		}
	}

	public void incrementInput(int i, double j) {
		double a = nodes.get(i).getMembranePotential();
		nodes.get(i).setMembranePotential(a+j);
	}

	public double getOutput(int index) {
		assert(index<nodes.size());
		return nodes.get(index).getActivationLevel();
	}
	
	public String toString()
	{
		String ret="";
		ret +="Layer { ActivationFunction: "+activationFunction+" name: "+name+"\n";
		
		
		for(Node node: nodes)
		{
			ret += "\t"+node.toString()+"\n";
		}
		ret +="}\n";
		
		
		
		return ret;
	}

	public void updateOutput() {
		for(Node node : nodes)
		{
			node.updateActivationLevel();
		}
	}

	public ActivationFunction getActivationFunction() {
		return activationFunction;
	}

	public void setTarget(int index, double target) {
		nodes.get(index).setTarget(target);
	}
	
	public void propagateError(){
		for(Node node : nodes)
			node.propageteError();
	}

	public void clearInError() {
		for(Node node : nodes)
			node.clearInError();
	}

	public void updateOutError() {
		List<Link> totalOutputLinks = getTotalOutputLinks();
		
		for(Node node : nodes)
			node.clearOutError();
		
		for(Link link: totalOutputLinks)
		{
			Module toModule = link.getToModule();
			for(Arc arc: link)
			{
				incrementOutError(arc.getFromIndex(),toModule.getInError(arc.getToIndex())*arc.getWeight());
			}
		}
	}

	public double getInError(int index) {
		return nodes.get(index).getInError();
	}

	public void incrementOutError(int index, double increment) {
		nodes.get(index).incrementOutError(increment);
	}

	public void incrementWeightDeltas() {
		return;
	}

	public void addWeightDeltas() {
		return;
	}

	public Layer getFirstLayer() {
		return this;
	}

	public Layer getLastLayer() {
		return this;
	}
}
